package ru.ksu.niimm.ose.ontology.impl;

import java.io.File;
import java.io.IOException;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import ru.ksu.niimm.ose.ontology.ArticleMetadata;
import ru.ksu.niimm.ose.ontology.OMDocElement;
import ru.ksu.niimm.ose.ontology.OMDocResourceFacade;
import ru.ksu.niimm.ose.ontology.OntologyResource;
import ru.ksu.niimm.ose.ontology.SourceReference;
import ru.ksu.niimm.ose.ontology.impl.util.SrcRefUtil;

@Deprecated
public class OMDocResourceFacadeOldImpl implements OMDocResourceFacade {
	private static final String FILE_URI_PREFIX = "file:/";
	private static final String XPATH_GET_ELEMENT_BY_ID_PATTERN = "//*[@id='%s']";
	private static final String STEX_SRCREF_ATTRIBUTE_NAME = "stex:srcref";
	private static final String DELIMITER = "#";

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ru.ksu.niimm.ose.ontology.impl.OMDocResourceLoader#load(com.hp.hpl.jena
	 * .rdf.model.Resource)
	 */
	public OMDocElement load(OntologyResource resource) {
		if (resource == null || resource.getUri() == null
				|| resource.getUri().equals(""))
			throw new IllegalArgumentException(
					"resource or resource URI cannot be null");

		String resourceUri = resource.getUri().trim();
		if (!resourceUri.contains(DELIMITER))
			throw new IllegalArgumentException(String.format(
					"incorrect format of resource URI: '%s' is absent",
					DELIMITER));

		StringTokenizer st = new StringTokenizer(resourceUri, DELIMITER);
		String omdocFileName = parseFileName(st.nextToken());
		String elementId = st.nextToken();
		Document doc = parseDocument(omdocFileName);
		String srcRefValue = retrieveSrcRefValue(doc, elementId);
		SourceReference sourceReference = SrcRefUtil.parse(resourceUri,
				srcRefValue);
		String pdfFileName = getPdfFileName(sourceReference.getFileName());
		ArticleMetadata articleMetadata = retriveArticleMetadata(doc);
		OMDocElement omdocElement = new OMDocElement(resourceUri, elementId,
				sourceReference);
		omdocElement.setArticleMetadata(articleMetadata);
		omdocElement.setPdfFileName(pdfFileName);
		return omdocElement;
	}

	private ArticleMetadata retriveArticleMetadata(Document doc) {
		// TODO: need more accurate search
		NodeList titleElement = doc.getElementsByTagName("dc:title");
		String title = titleElement != null && titleElement.item(0) != null ? titleElement
				.item(0).getTextContent()
				: null;
		NodeList creatorElement = doc.getElementsByTagName("dc:creator");
		String author = creatorElement != null
				&& creatorElement.item(0) != null ? creatorElement.item(0)
				.getTextContent() : null;
		// TODO : correct initialization with URI
		ArticleMetadata articleMetadata = new ArticleMetadata(null);
		articleMetadata.setTitle(title);
//		articleMetadata.setAuthor(author);
		return articleMetadata;
	}

	private static String getPdfFileName(String omdocFileName) {
		// PDF file name is generated by convention: f.e. "example.tex" ->
		// "example.pdf"
		int dotIndex = omdocFileName.indexOf(".");
		String pureFileName = omdocFileName.substring(0, dotIndex);
		return String.format("%s.pdf", pureFileName);
	}

	private String parseFileName(String string) {
		// TODO : bad implementation, need more accurate parse file name string
		String clearedString = string.startsWith(FILE_URI_PREFIX) ? string
				.replaceFirst(FILE_URI_PREFIX, "") : new String(string);
		return clearedString.startsWith("/") ? clearedString : String.format(
				"/%s", clearedString);

	}

	private String retrieveSrcRefValue(Document doc, String elementId) {
		String srcRefValue = null;

		try {
			Node node = findNodeByElementId(doc, elementId);
			NamedNodeMap attributes = node.getAttributes();
			for (int i = 0; i < attributes.getLength(); i++) {
				Node attribute = attributes.item(i);
				if (attribute.getNodeName().equals(STEX_SRCREF_ATTRIBUTE_NAME)) {
					srcRefValue = attribute.getNodeValue();
					break;
				}
			}
			return srcRefValue;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	private Node findNodeByElementId(Document doc, String elementId)
			throws ParserConfigurationException, SAXException, IOException,
			XPathExpressionException {
		XPathFactory xPathFactory = XPathFactory.newInstance();
		XPath xpath = xPathFactory.newXPath();
		XPathExpression expr = xpath.compile(String.format(
				XPATH_GET_ELEMENT_BY_ID_PATTERN, elementId));

		Object result = expr.evaluate(doc, XPathConstants.NODE);
		Node node = (Node) result;
		return node;
	}

	private Document parseDocument(String documentUri) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// TODO : need to add namespace awareness and implement namespace
		// resolver to use namespaces in XPath expressions
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(new File(documentUri));
			return doc;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}
}
